package com.dahuyou.netty.nio.channel;

import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

public class ChannelTest {

    @Test
    public void createFileChannel() throws Exception {
        String srcFile = "d:\\test\\Snipaste_2024-09-02_14-29-46.png";
        String destFile = "d:\\test\\Snipaste_2024-09-02_14-29-46.png";
        //创建一个文件输入流
        FileInputStream fis = new FileInputStream(srcFile);
        //获取文件流的通道
        FileChannel inChannel = fis.getChannel();
        //创建一个文件输出流
        FileOutputStream fos = new FileOutputStream(destFile);
        //获取文件流的通道
        FileChannel outchannel = fos.getChannel();
        //也可以通过RandomAccessFile文件随机访问类，获取FileChannel文件通道实例，代码如下：
        // 创建RandomAccessFile随机访问对象
        RandomAccessFile rFile = new RandomAccessFile("filename.txt", "rw");
        //获取文件流的通道（可读可写）
        FileChannel channel = rFile.getChannel();
    }

    @Test
    public void readFileChannelTest() throws Exception {
        // 文件编码是utf8,需要用utf8解码
        Charset charset = Charset.forName("utf-8");
        CharsetDecoder decoder = charset.newDecoder();

        // 创建RandomAccessFile随机访问对象
        RandomAccessFile rFile = new RandomAccessFile("d:\\test\\aaaa.txt", "rw");
        //获取文件流的通道（可读可写）
        FileChannel fChannel = rFile.getChannel();
        ByteBuffer bBuf = ByteBuffer.allocate(32); // 缓存大小设置为32个字节。仅仅是测试用。
        CharBuffer cBuf = CharBuffer.allocate(32);

        int bytesRead = fChannel.read(bBuf); // 从文件通道读取字节到buffer.
        char[] tmp = null; // 临时存放转码后的字符
        byte[] remainByte = null;// 存放decode操作后未处理完的字节。decode仅仅转码尽可能多的字节，此次转码不了的字节需要缓存，下次再转
        int leftNum = 0; // 未转码的字节数
        while (bytesRead != -1) {

            bBuf.flip(); // 切换buffer从写模式到读模式
            decoder.decode(bBuf, cBuf, true); // 以utf8编码转换ByteBuffer到CharBuffer
            cBuf.flip(); // 切换buffer从写模式到读模式
            remainByte = null;
            leftNum = bBuf.limit() - bBuf.position();
            if (leftNum > 0) { // 记录未转换完的字节
                remainByte = new byte[leftNum];
                bBuf.get(remainByte, 0, leftNum);
            }

            // 输出已转换的字符
            tmp = new char[cBuf.length()];
            while (cBuf.hasRemaining()) {
                cBuf.get(tmp);
                System.out.print(new String(tmp));
            }

            bBuf.clear(); // 切换buffer从读模式到写模式
            cBuf.clear(); // 切换buffer从读模式到写模式
            if (remainByte != null) {
                bBuf.put(remainByte); // 将未转换完的字节写入bBuf，与下次读取的byte一起转换
            }
            bytesRead = fChannel.read(bBuf);
        }
        rFile.close();
    }


    @Test
    public void writeFileChannelTest() throws Exception {
        File file = new File("d:\\test\\jj.txt");
        if (!file.exists()) file.createNewFile();

        RandomAccessFile randomAccessFile = new RandomAccessFile("d:\\test\\jj.txt", "rw");
        FileChannel channel = randomAccessFile.getChannel(); // 获取一个可读写文件通道

        ByteBuffer buf = ByteBuffer.allocate(5);
        byte[] data = "Hello, Java NIO.".getBytes();
        for (int i = 0; i < data.length; ) {
            buf.put(data, i, Math.min(data.length - i, buf.limit() - buf.position()));
            buf.flip();
            // 返回写入数据的数量
            i += channel.write(buf);
//            buf.compact();
            buf.clear(); // 写入的都读完了，所以调用compact和调用clear效果一样
        }
        channel.force(false);
        channel.close();
    }

}
